#pragma once
#include <iostream>
#include <string>
#include "Socket.hpp"
#include "Log.hpp"
#include <memory>
#include "InetAddr.hpp"
#include <sys/epoll.h>

using namespace socket_ns;

class EpollServer
{
    const static int gnum = 64; // 事件数组大小
public:
    EpollServer(uint16_t port = 8888) : _port(port), _listenSock(std::make_unique<TcpSocket>()), _epfd(-1)
    {
        // 1. 创建listensock
        InetAddr addr("0", _port);
        _listenSock->BuildListenSocket(addr);

        // 2. 创建epoll模型
        _epfd = epoll_create(120); // 创建epoll实例 参数不要小于0即可
        if (_epfd < 0)
        {
            LOG(FATAL, "epoll_create error\n");
            exit(5);
        }
        LOG(DEBUG, "epoll_create success,epfd:%d \n", _epfd); // 文件描述符
        // 3. 只有一个listensock, listen sock 关心的事件：读事件
        struct epoll_event ev;              // epoll事件结构体
        ev.events = EPOLLIN;                // 监听读事件
        ev.data.fd = _listenSock->SockFd(); // 监听套接字

        epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenSock->SockFd(), &ev); // 将监听套接字加入epoll实例
    }
    ~EpollServer()
    {
        _listenSock->Close();
        if (_epfd >= 0) // 如果epoll实例存在
        {
            ::close(_epfd); // 关闭epoll实例
        }
    }

    void HandlerEvent(int num)
    {
        for (int i = 0; i < num; i++)
        {
            uint32_t revents = _revs[i].events; // 获取事件
            int sockfd = _revs[i].data.fd;      // 获取文件描述符
            if (revents & EPOLLIN)              // 如果是读事件
            {
                if (sockfd == _listenSock->SockFd()) // 如果是监听套接字
                {
                    InetAddr clientaddr;
                    int newfd = _listenSock->Accepter(&clientaddr); // 接受连接
                    if (newfd < 0)
                        continue; // 如果接受失败则跳过

                    // 获取新链接成功
                    // 读取或者写入呢？不能！谁知道newfd上面有对应的事件就绪了呢？epoll
                    struct epoll_event ev; // epoll事件结构体
                    ev.events = EPOLLIN;   // 监听读事件
                    ev.data.fd = newfd;    // 监听套接字

                    epoll_ctl(_epfd, EPOLL_CTL_ADD, newfd, &ev); // 将监听套接字加入epoll实例
                    LOG(DEBUG, "_listensock ready ,accept done,epoll_ctl done,newfd is:%d \n", newfd);
                }
                else
                {
                    char buffer[1024];
                    ssize_t n = ::recv(sockfd, buffer, sizeof(buffer), 0); // 接收数据
                    if (n > 0)
                    {
                        LOG(DEBUG, "normal fd %d read,recv begin...\n", sockfd);
                        buffer[n] = 0; // 结束符
                        std::cout << "client say# " << buffer << std::endl;

                        std::string echo_string = "server echo# ";
                        echo_string += buffer;
                        ::send(sockfd, echo_string.c_str(), echo_string.size(), 0); // 将数据发送给客户端
                    }
                    else if (n == 0)
                    {
                        // 对端连接关闭了
                        LOG(DEBUG, "normal fd %d close,me too!\n", sockfd);
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr); // 将连接从epoll实例中删除
                        ::close(sockfd);                                  // 关闭连接
                    }
                    else
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr); // 将连接从epoll实例中删除
                        ::close(sockfd);                                  // 关闭连接
                    }
                }
            }
        }
    }

    void Loop()
    {
        int timeout = 1000; // 超时时间
        while (1)
        {
            int n = epoll_wait(_epfd, _revs, gnum, -1); // 等待事件发生  时间为-1阻塞等待 0非阻塞等待
            switch (n)
            {
            case 0:
                LOG(DEBUG, "epoll_wait timeout...\n");
                break;
            case -1:
                LOG(DEBUG, "epoll_wait failed...\n");
                break;
            default:
                LOG(DEBUG, "epoll_wait haved event ready...\n");
                HandlerEvent(n);
                break;
            }
        }
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listenSock; // 监听套接字
    int _epfd;                           // epoll套接字

    struct epoll_event _revs[gnum]; // 事件数组
};